#pragma once

#include "../Brite/Ray.h"
#ifdef DOUBLE_PRECISION_TRIANGLES
#include "../Brite/TriangleDP.h"
#else
#include "../Brite/Triangle.h"
#endif
#include "../Brite/Parallelogram.h"
#include "../Brite/Scene.h"

#include "../Utility/HiPerfTimer.h"
#include "../io/Vertex.h"
#include "../Utility/UtilityFunctions.h"
#include "../Utility/D3D/D3DUtilityFunction.h"

#pragma push_macro("ASSERT")
#pragma push_macro("THROW")
#undef ASSERT
#undef THROW

#include "ExrFileIO.h"

#pragma pop_macro("THROW")
#pragma pop_macro("ASSERT")

enum HIERBUILDSTYLE
{
	FlatList = 0,
	NaiveMiddleSplit,
	NaiveMedianSplit,
	GreedySplit,
};

enum RAYBOUNCETYPE
{
	RAYMISSEDGEOMETRY = 0,
	RAYHITNODATAPT,
	RAYHITNODATAPT_MBOUNCES,
	RAYFIRSTBOUNCE,
	RAYMULTIPLEBOUNCES,	
};

class RayWithResult {
public:
	float originX,originY,originZ;
	float dirX,dirY,dirZ;
	float tStart,tEnd,tResult;
	void constructRay(Ray &ray) const {
		ray.setOrigin(originX,originY,originZ);
		ray.setDirection(dirX,dirY,dirZ);
		ray.setTParameters(tStart,tEnd);
		assert(originX==ray.originX());
	}
};

class CRayTracingHM
{
public:
	CRayTracingHM();
	virtual ~CRayTracingHM();
	bool loadGeometryFromFile(const char *strSceneFN);
	bool loadRaysFromFile(const char *strRayFN);
	bool createGeometryFrom2DVertArr(const std::vector<VertexNorm>& arrVert, unsigned int iWidth, unsigned int iHeight);
	bool createRaysIn2DPlane(const D3DXVECTOR2& vLeftTopPt, float f2dDataWidth, float f2dDataHeight, float fScaleRatio, float fDistToData,
		const D3DXVECTOR3& vRayDir);
	bool buildSceneHierarchy();
	bool Tracing2dHeightMapData(const CXYZFileIO& curHeightMapFile, float fScaleRatio, const D3DXVECTOR3& vRayDir, const char* strOutputFN);
	bool Tracing2dHeightMapData_RayOrder(const CXYZFileIO& curHeightMapFile, const float fScaleRatio, const D3DXVECTOR3& vRayDir, const char* strOutputFN);
	bool Tracing2dHMDataVirutalGonio(const CXYZFileIO& curHeightMapFile, const float fScaleRatio, const D3DXVECTOR3& vRayDir, 
		const char* strOutputFN, const char* strSumFN, const char* strFirstFN, const char* strMultiFN, 
		const double iorIncidentReal, const double iorTransmittedReal, const double iorTransmittedImaginary);
	bool Tracing2dHMDataVirutalGonio_OneOfMultiXYZFiles(const CXYZFileIO& curHeightMapFile, const float fScaleRatio, const D3DXVECTOR3& vRayDir, 
		double* arrSumBuf, double* arrSingleBuf, double* arrMultiBuf, unsigned int iArrBufWidth, unsigned int iArrBufHeight, 
		const double iorIncidentReal, const double iorTransmittedReal, const double iorTransmittedImaginary);
	static void SaveTo2dGonioBuf(const D3DXVECTOR3& vVec, const double fEnergyCurVec, double* arrStoreBuf, unsigned int iBufWidth, unsigned int iBufHeight);
	static void Save2dGonioBufTo8BitImg(const double* arrStoreBuf, unsigned int iBufWidth, unsigned int iBufHeight, const char* strImgFN, 
		const double fMinVal, const double fMaxVal, bool bColor=true);

	static void Save2dGonioBufTo16BitImg(const double* arrStoreBuf, unsigned int iBufWidth, unsigned int iBufHeight, const char* strImgFN, 
		const double fMinVal, const double fMaxVal, bool bColor=true);

	//OUTPUT DEBUG INFO
	void OutputDebugInfoThread(UtilityString& strDbgInfo)
	{
		CString* pOutputStr = new CString(strDbgInfo.GetCharStr());
		theApp.PostThreadMessage(WM_OUTPUT_DEBUGMSGTHREAD, WPARAM(pOutputStr),0);
	}

	unsigned int getVGonioBufWidth() {return m_iVGonioOutputImgWidth;}
	unsigned int getVGonioBufHeight() {return m_iVGonioOutputImgHeight;}

protected:
	Scene* m_pScene;
	CGrowableArray<Ray> m_arrRays;
	CGrowableArray<D3DXVECTOR3> m_arrTriNormals;
	HIERBUILDSTYLE m_iCurHierBldStyle;
	unsigned int m_iNumRaysPerRowIn2D;
	//ray tracing epsilon
	static const float ExtraEpsilon;
	//virtual gonio
	unsigned int m_iVGonioOutputImgWidth;
	unsigned int m_iVGonioOutputImgHeight;
	double m_fTotalIncidentEnergy;
};
